#include "tile/slopingrighttile.hpp"

#include "actor.hpp"
#include "graphics.hpp"
#include "tile/tilemap.hpp"

namespace nmc
{
	SlopingRightTile::SlopingRightTile(const Point& tileMapPosition, TileMap* tileMap)
		:Tile(Tile::SLOPING_RIGHT, tileMapPosition, tileMap),
		mSolidBottom(true),
		mSolidLeft(true),
		mConnectedToASlopingRightTile(false),
		mRightEndOfSlope(false),
		mNearARoof(false)
	{

	}

	void SlopingRightTile::stickToFloor(Actor* actor, Point& velocity)
	{
	}

	void SlopingRightTile::resolveCollision(Actor* actor, Point& velocity)
	{
        /*
        const Point actorBCP = actor->getBottomCollisionPoint();

		// Check if the actor will be anywhere near the tile.
		// If it's not then we know we don't have a collision.
		if (actorBCP.x < getWorldPosition().x 
			&& actorBCP.y < getWorldPosition().y)
		{
			return;
		}

		// If this tile is near a roof we don't want the actor to be able
		// to go through the roof and we therefore stop him if he moves
		// to the right or upwards. If we would not then this tile might
		// push the actor upwards resulting after the solid tiles above
		// have checked their collision resulting in the actor being able
		// to move through the roof.
		if (mNearARoof
			&& (velocity.x < 0 || velocity.y < 0) // Actor moving left or upwards.
			&& actorBCP.y < getWorldPosition().y + getHeight()) // Actor bottom collision center is below the tile.
		{
			velocity.x = 0;
			velocity.y = 0;
			return;
		}
		
		// If this tile is connected to a sloping right tile
		// then it should be considered an empty tile if the actor
		// moves along the slope of the connected tile so this tile
		// won't stop the actor until the actor is safely on this
		// tile's slope.
		if (mConnectedToASlopingRightTile
			&& actorBCP.x >= getWorldPosition().x + getWidth() // Actor is right of the tile.
			&& actorBCP.y > getWorldPosition().y + getHeight()) // Actor bottom collision center is below the tile.
		{
			return;
		}

		// If this tile is an end of a slope and there is a steep just next to this tile
		// then we shouln't let the actor leave the slope until the actor is completely 
		// outside of this tile. This will result in the actor moving only horizontally if
		// the actor has hit the bottom of the slope but still is inside the tile.
		if (mRightEndOfSlope
			&& velocity.y > 0 // Actor is moving downwards.
			&& actorBCP.x >= getWorldPosition().x + getWidth() // Actor bottom center collision point is right of tile.
			&& actorBCP.y <= getWorldPosition().y + getHeight() // Actor in or above the tile
			&& actor->getPosition().y + velocity.y + actor->getHeight() > getWorldPosition().y + getHeight()) // Actor is below the tile
		{
			int yCorrection = actor->getPosition().y + velocity.y + actor->getHeight() - (getWorldPosition().y + getHeight());
			velocity.y -= yCorrection;
			return;
		}

		// If the actor is moving downwards and has its bottom collision center
		// left of the tile and above the tile, then we have a collision.
		if (velocity.y != 0 // Actor is moving downwards.
			&& actorBCP.x <= getWorldPosition().x  // Actor has its bottom center collision point left of the tile.
			&& actorBCP.y < getWorldPosition().y) // Actor is above the tile.
		{
			int yCorrection = actor->getPosition().y  + velocity.y + actor->getHeight() - getWorldPosition().y;
			velocity.y -= yCorrection;
			return;
		}

		// If the actor has its bottom collision center below the tile and
		// its bottom collision center right of the tile and
		// tries to move to the left into the tile we have a collision.
		if (velocity.x < 0 // Actor is moving to the left.
			&& actorBCP.x >= getWorldPosition().x + getWidth() // Actor has its bottom center collision point right of the tile.
			&& actor->getPosition().x >= getWorldPosition().x + getWidth() // Actor is right of the tile.
			&& actorBCP.y >= getWorldPosition().y + getHeight() // Actor has its bottom center collision point below the tile.
			&& getWorldPosition().x + getWidth() >= actor->getPosition().x + velocity.x) // Actor will be in the tile.
		{
			int xCorrection = getWorldPosition().x + getWidth() - (actor->getPosition().x + velocity.x);
			velocity.x += xCorrection;
			return;
		}
		
		// If the tile is solid at the bottom and the actor tries to move
		// upwards into the tile we have a collision.
		if (mSolidBottom
			&& velocity.y < 0 // Actor is moving upwards.
			&& actor->getPosition().y >= getWorldPosition().y + getHeight() // Actor is below the tile.
			&& getWorldPosition().y + getHeight() > actor->getPosition().y + velocity.y) // Actor will be in the tile.
		{
			int yCorrection = getWorldPosition().y + getHeight() - (actor->getPosition().y + velocity.y);
			velocity.y += yCorrection;
			return;
		}

		// If the tile is solid to the left and the tries to move to the right into
		// the tile we have a collision.
		if (mSolidLeft
			&& velocity.x > 0 // Actor is moving to the right.
			&& actor->getPosition().x  + actor->getWidth() <= getWorldPosition().x // Actor right of the tile.
			&& getWorldPosition().x < actor->getPosition().x + velocity.x + actor->getWidth()) // Actor will be in the tile.
		{
			int xCorrection = (actor->getPosition().x + velocity.x + actor->getWidth()) - getWorldPosition().x;
			velocity.x -= xCorrection;
			return;
		}
        */
	}

    bool SlopingRightTile::isStandingOnFloor(Actor* actor)
	{
		return false;
	}

	void SlopingRightTile::calculateSolidity(TileMap* tileMap)
	{
		Tile* left = tileMap->getTile(getTileMapPosition().x - 1, 
									  getTileMapPosition().y);
		Tile* bottom = tileMap->getTile(getTileMapPosition().x, 
										getTileMapPosition().y + 1);
		Tile* bottomRight = tileMap->getTile(getTileMapPosition().x + 1,
			                                getTileMapPosition().y + 1);
		Tile* roof = tileMap->getTile(getTileMapPosition().x,
			                          getTileMapPosition().y - 2);

		mSolidLeft = left->getType() != Tile::SOLID
			&& left->getType() != Tile::SLOPING_LEFT;

		mSolidBottom = bottom->getType() != Tile::SOLID;

		mConnectedToASlopingRightTile = bottomRight->getType() == Tile::SLOPING_RIGHT;
		
		mRightEndOfSlope = bottomRight->getType() == Tile::EMPTY;

		mNearARoof = roof->getType() == Tile::SOLID;
	}

	void SlopingRightTile::draw(Graphics* graphics)
	{

	}

	void SlopingRightTile::drawType(Graphics* graphics)
	{
		graphics->setBlendMode(Graphics::ALPHA);
		graphics->setColor(Color(0xffffff80));
		
		graphics->drawLine(getWorldPosition().x, 
						   getWorldPosition().y,
						   getWorldPosition().x + Tile::SIZE - 1,
						   getWorldPosition().y + Tile::SIZE - 1);
		graphics->drawLine(getWorldPosition().x, 
						   getWorldPosition().y,
						   getWorldPosition().x,
						   getWorldPosition().y + Tile::SIZE - 1);
		graphics->drawLine(getWorldPosition().x,
						   getWorldPosition().y + Tile::SIZE - 1,
						   getWorldPosition().x + Tile::SIZE - 1,
						   getWorldPosition().y + Tile::SIZE - 1);
	}

	void SlopingRightTile::drawSolidity(Graphics* graphics)
	{   
        graphics->setColor(Color(0xff0000));

		if (mSolidBottom)
		{
			graphics->drawLine(getWorldPosition().x, 
							   getWorldPosition().y + Tile::SIZE - 1, 
							   getWorldPosition().x + Tile::SIZE - 1,
							   getWorldPosition().y + Tile::SIZE - 1);
		}

		if (mSolidLeft)
		{
			graphics->drawLine(getWorldPosition().x, 
							   getWorldPosition().y, 
							   getWorldPosition().x,
							   getWorldPosition().y + Tile::SIZE - 1);
		}

        graphics->setColor(Color(0x00ff00));
		graphics->drawLine(getWorldPosition().x, 
						   getWorldPosition().y,
						   getWorldPosition().x + Tile::SIZE - 1,
						   getWorldPosition().y + Tile::SIZE - 1);

		Tile::drawSolidity(graphics);
	}
}